#ifndef MAPPER_H
#define MAPPER_H

#include "CPUOpcodes.h"
#include "Cartridge.h"
#include "pch.h"
#include <memory>
#include <functional>

PNE_NAMESPACE_BEGIN
enum class NameTableMirroring
{
    Horizontal = 0,
    Vertical = 1,
    FourScreen = 8,
    OneScreenLower,
    OneScreenHigher,
};

struct Mapper
{
public:
    enum class Type : unsigned int
    {
        NROM = 0,
        SxROM = 1,
        UxROM = 2,
        CNROM = 3,
        MMC3 = 4,
        AxROM = 7,
        ColorDreams = 11,
        GxROM = 66
    };

    Mapper(Cartridge &cart, Type t) : m_cartridge(cart), m_type(t) {}

    virtual ~Mapper() = default;
    // interface expose
    virtual void WritePRG(Address addr, Byte value) = 0; // interface
    virtual Byte ReadPRG(Address addr) = 0;              // interface

    virtual Byte ReadCHR(Address addr) = 0;
    virtual void WriteCHR(Address addr, Byte byte) = 0;
    // end interface expose

    virtual NameTableMirroring GetNameTableMirroring();

    bool inline hasExtendedRAM()
    {
        return m_cartridge.HasExtendedRAM();
    }

    virtual void ScanLineIRQ() {}

    static std::unique_ptr<Mapper> CreateMapper(Type mapper_t, Cartridge &cart, std::function<void()> interrupt_cb, std::function<void(void)> mirroring_cb);

protected:
    Cartridge &m_cartridge;
    Type m_type;
};

PNE_NAMESPACE_END
#endif // MAPPER_H
// DONE
